<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Gab - Chapter 6</title>
	<link rel="stylesheet" href="/strophe/public/css/jquery-ui-1.8.21.custom.css">
	<link rel="stylesheet" href="/strophe/public/css/gab.css">
	<script type="text/javascript" src="/strophe/public/js/jquery-1.7.2.min.js"></script>
	<script type="text/javascript" src="/strophe/public/js/jquery-ui-1.8.21.custom.min.js"></script>
	<script type="text/javascript" src="/strophe/public/js/strophe.js"></script>
	<script type="text/javascript" src="/strophe/public/js/flXHR.js"></script>
	<script type="text/javascript" src="/strophe/public/js/strophe.flxhr.js"></script>
	<script type="text/javascript" src="/strophe/public/js/chat.js"></script>
	<script type="text/javascript">
		var Gab = {
			connection: null,
			pendingSubscriber: null,
			
			onRoster: function(iq) {
				$(iq).find('item').each(function() {
					var jid = $(this).attr('jid');
					var name = $(this).attr('name') || jid;
					
					// transform jid into an id
					var jid_id = Gab.getIdFromJid(jid);
					
					var contact= $("<li id='" + jid_id + "'>"
							+ "<div class='roster-contact offline'>"
							+ "<div class='roster-name'>" + name + "</div>"
							+ "<div class='roster-jid'>" + jid + "</div>"
							+ "</div></li>");
					
// 					Gab.log(jid_id + " is inserted.");
					
					Gab.insertContact(contact);
				});
			},
			
			onRosterChanged: function(iq) {
				Gab.log("roster changed.");
				
				$(iq).find('item').each(function() {
					var sub = $(this).attr('subscription');
					var jid = $(this).attr('jid');
					var name = $(this).attr('name') || jid;
					var jid_id = Gab.getIdFromJid(jid);
					
// 					Gab.log(jid + ": " + name + ", " + sub);
					
					if (sub == 'remove') {
						// contact is being removed
						$('#' + jid_id).remove();
					}
					else {
						// contact is being added or modified
						var contact = $("<li id='" + jid_id + "'>"
							+ "<div class='" + ($('#' + jid_id).find('.roster-contact').attr('class') || "roster-contact offline") + "'>"
							+ "<div class='roster-name'>" + name + "</div>"
							+ "<div class='roster-jid'>" + jid + "</div>"
							+ "</div></li>");
							
						if ($('#' + jid_id).length > 0) {
							$('#' + jid_id).replaceWith(contact);
						}
						else {
							Gab.insertContact(contact);
						}
						
						Gab.log("onRosterChange: id: " + jid_id + ", class: " + $('#' + jid_id).find('.roster-contact').attr('class'));
					}
				});
				
				return true;
			},
			
			onPresence: function(presence) {
				var ptype = $(presence).attr('type');
				var from = $(presence).attr('from');
				
// 				Gab.log("onPresence: " + from + ": " + ptype);
				
				if (ptype == 'subscribe') {
					// populate pendingSubscriber, the apprive-jid span, and open the dialog
					Gab.pendingSubscriber = from;
					$('#approve-jid').text(Strophe.getBareJidFromJid(from));
					$('#approve_dialog').dialog('open');
				}
				else if (ptype != 'error') {
					var contact = $('#roster-area li#' + Gab.getIdFromJid(from)).find('.roster-contact')
							.removeClass('online')
							.removeClass('away')
							.removeClass('offline');
					
					if (ptype == 'unavailable') {
						contact.addClass('offline');
					}
					else {
						var show = $(presence).find('show').text();
						if (show == "" || show == "chat") {
							contact.addClass('online');
						}
						else {
							contact.addClass('away');
						}
					}
					
					var li = contact.parent();
					li.remove();
					Gab.insertContact(li);
				}
				
				// reset addressing for user since their presence changed
				var jid_id = Gab.getIdFromJid(from);
				ChatManager.setJid('#chat-' + jid_id, Strophe.getBareJidFromJid(from));
				
				return true;
			},
			
			onMessage: function(message) {
				var fullJid = $(message).attr('from')
				var jid = Strophe.getBareJidFromJid(fullJid);
				var jid_id = Gab.getIdFromJid(jid);
				var name = Strophe.getNodeFromJid(jid);
				
				var area = '#chat-area';
				var tab = '#chat-' + jid_id;
				if ($(tab).length == 0) {
					ChatManager.addTab(area, tab, jid, fullJid);
				}
				
				// Once message arrived, reset the jid with the full jid address to send messages only to the specified user
				ChatManager.setJid(tab, fullJid);
				ChatManager.selectTab(area, tab);
				
				// check if the status is composing
				var composing = $(message).find('composing');
				if (composing.length > 0) {
					ChatManager.showComposing(tab, name);
				}
				
				var body = $(message).find("html > body");
				
				if (body.length == 0) {
					body = $(message).find('body');
					if (body.length > 0) {
						body = body.text();
					}
					else {
						body = null;
					}
				}
				else {
					body = body.contents();
					
					var span = $("<span></span>");
					body.each(function() {
						if (document.importNode) {
							$(document.importNode(this, true)).appendTo(span);
						}
						else {
							// IE workaround
							span.append(this.xml);
						}
					});
					
					body = span;
				}
				
				if (body) {
					// remove notification since user is now active
					ChatManager.removeComposing(tab);
					
					// add the new message
					ChatManager.showMessage(tab, name, body, jid_id, false);
				}
				
				return true;
			},
			
			getIdFromJid: function(jid) {
				return Strophe.getBareJidFromJid(jid).replace(/@/g, "-").replace(/\./g, "-");
			},
			
			presenceValue: function(element) {
				if (element.hasClass('online')) {
					return 2;
				}
				else if (element.hasClass('away')) {
					return 1;
				}
			
				return 0;
			},
			
			insertContact: function(contact) {
				var jid = contact.find('.roster-jid').text();
				var pres = Gab.presenceValue(contact.find('.roster-contact'));
				
				// log
// 				Gab.log("insertContact: " + jid + ": " + pres);
				
				var contacts = $('#roster-area li');
				
				if (contacts.length > 0) {
					var inserted = false;
					contacts.each(function() {
						var cmp_pres = Gab.presenceValue($(this).find('.roster-contact'));
						var cmp_jid = $(this).find('.roster-jid').text();
						
						if (pres > cmp_pres) {
							$(this).before(contact);
							inserted = true;
							return false;
						}
						else if (pres == cmp_pres) {
							if (jid < cmp_jid) {
								$(this).before(contact);
								inserted = true;
								return false;
							}
						}
					});
					
					if (!inserted) {
						$('#roster-area ul').append(contact);
					}
				}
				else {
					$('#roster-area ul').append(contact);
				}
			},
			
			scrollChat: function(jid) {
				
			},
			
			log: function(message) {
				$('#log').prepend("<div>" + message + "</div>");
			}
		};
	
		$(document).ready(function() {
			$('#login_dialog').dialog({
				autoOpen: true,
				draggable: false,
				modal: true,
				title: 'Connect to XMPP',
				buttons: {
					"Connect": function() {
						$(document).trigger('connect', {
							jid: $('#jid').val(),
							password: $('#password').val()
						});
						
						$('#password').val('');
						$(this).dialog('close');
					}
				}
			});
			
			$('#contact_dialog').dialog({
				autoOpen: false,
				draggable: false,
				modal: true,
				title: 'Add a Contact',
				buttons: {
					"Add": function() {
						$(document).trigger('contact_added', {
							jid: $('#contact-jid').val(),
							name: $('#contact-name').val()
						});
						
						$('#contact-jid').val('');
						$('#contact-name').val('');
						
						$(this).dialog('close');
					}
				}
			});
			
			$('#new-contact').click(function(ev) {
				$('#contact_dialog').dialog('open');
			});
			
			$('#new-chat').click(function() {
				$('#chat_dialog').dialog('open');
			});
			
			$('#disconnect').click(function(ev) {
				Gab.connection.disconnect();
			});
			
			$('#approve_dialog').dialog({
				autoOpen: false,
				draggable: false,
				modal: true,
				title: "Subscription Request",
				buttons: {
					"Deny": function() {
						Gab.connection.send($pres({to: Gab.pendingSubscriber, type: "unsubscribed"}));
						Gab.pendingSubscriber = null;
						
						$(this).dialog('close');
					},
					
					"Approve": function() {
						Gab.connection.send($pres({to: Gab.pendingSubscriber, type: "subscribed"}));
						
						// send subscription request
						Gab.connection.send($pres({to: Gab.pendingSubscriber, type: "subscribe"}));
						
						Gab.pendingSubscriber = null;
						$(this).dialog('close');
					}
				}
			});
			
			// configure new chat dialog
			$('#chat_dialog').dialog({
				autoOpen: false,
				draggable: false,
				modal: true,
				title: "Start a Chat",
				buttons: {
					"Start" : function() {
						var jid = $('#chat-jid').val();
						var jid_id = Gab.getIdFromJid(jid);
						
						ChatManager.addTab('#chat-area', '#chat-' + jid_id, jid, jid);
						
						$('#chat-jid').val('');
						$(this).dialog('close');
					}
				}
			});
			
			// initialize chat area
			$('#chat-area').tabs().find('.ui-tabs-nav').sortable({axis: 'x'});
			
			$('.roster-contact').live('click', function() {
				var li = $(this).parent();
				
				var jid = li.find('.roster-jid').text();
				var name = li.find('.roster-name').text();
				var jid_id = Gab.getIdFromJid(jid);
				
				Gab.log("initialize chat area: " + jid + ", " + name);
				
				var tab = '#chat-' + jid_id;
				if ($(tab).length > 0) {
					ChatManager.selectTab('#chat-area', tab);
				}
				else {
					ChatManager.addTab('#chat-area', tab, name, jid);
				}
			});
			
			// initialize chat input box
			$('.chat-input').live('keypress', function(ev) {
				var tab = $(this).parent();
				var jid = ChatManager.getJid(tab);
				
				if (ev.which == 13) {
					ev.preventDefault();
					
					var body = $(this).val();
					var message = $msg({to: jid, type: "chat"})
							.c('body').t(body).up()
							.c('active', {xmlns: "http://jabber.org/protocol/chatstates"});
					
					Gab.connection.send(message);
					ChatManager.showMessage(tab, Strophe.getNodeFromJid(Gab.connection.jid), body, Gab.getIdFromJid(jid), true);
					
					$(this).val('');
					ChatManager.setComposing(tab, false);
				}
				else {
					var composing = ChatManager.getComposing(tab);
					if (!composing) {
						var notify = $msg({to:jid, type: "chat"})
								.c('composing', {xmlns: "http://jabber.org/protocol/chatstates"});
						
						Gab.connection.send(notify);
						
						ChatManager.setComposing(tab, true);
					}
				}
			});
		});
		
		$(document).bind('connect', function(ev, data) {
			var boshUrl = "${config.boshUrl}";
			var conn = new Strophe.Connection(boshUrl);
			
			$('#status').text("Connecting to " + boshUrl);
			
			conn.connect(data.jid, data.password, function(status) {
				if (status == Strophe.Status.CONNECTED) {
					$(document).trigger('connected');
				}
				else if (status == Strophe.Status.DISCONNECTED) {
					$(document).trigger('disconnected');
				}
			});
			Gab.connection = conn;
		});
		
		$(document).bind('connected', function() {
			$('#status').text("Connected to XMPP server.");
			
			// query roster
			var iq = $iq({type: "get"}).c("query", {xmlns: "jabber:iq:roster"});
			Gab.connection.sendIQ(iq, Gab.onRoster);
			
			// register handlers
			Gab.connection.addHandler(Gab.onRosterChanged, "jabber:iq:roster", "iq", "set");
			Gab.connection.addHandler(Gab.onMessage, null, "message", "chat");
			
			// send presence
			Gab.connection.addHandler(Gab.onPresence, null, "presence");
			Gab.connection.send($pres());
		});
		
		$(document).bind('disconnected', function() {
			$('#status').text("Disconnected from XMPP server.");
			
			Gab.connection = null;
			Gab.pendingSubscriber = null;
			
			$('#roster-area ul').empty();
			$('#chat-area ul').empty();
			$('#chat-area div').empty();
			
			$('#login_dialog').dialog('open');
		});
		
		$(document).bind('contact_added', function(ev, data) {
			var iq = $iq({type: "set"}).c("query", {xmlns: "jabber:iq:roster"}).c("item", data);
			Gab.connection.sendIQ(iq);
			
			var subscribe = $pres({to: data.jid, "type": "subscribe"});
			Gab.connection.send(subscribe);
		})
	</script>
</head>
<body>
	<h1>Gab</h1>
	
	<div id="top">
		<div id="status"></div>
		<div id="toolbar">
			<span class="button" id="new-contact">add contact..</span> ||
			<span class="button" id="new-chat">chat with..</span> ||
			<span class="button" id="disconnect">disconnect</span>		
		</div>
	</div>	
	
	<div id="chat-area">
		<ul></ul>
	</div>

	<div id="roster-area">
		<ul></ul>
	</div>
	
	<div id="log"></div>
	
	<!-- login dialog -->
	<div id="login_dialog" class="hidden">
		<label>JID:</label><input type="text" id="jid" value="sejoonlim@${config.xmppDomain}">
		<label>Password:</label><input type="password" id="password" value="welcome1">
	</div>
	
	<!-- contact dialog -->
	<div id="contact_dialog" class="hidden">
		<label>JID:</label><input type="text" id="contact-jid">
		<label>Name:</label><input type="text" id="contact-name">
	</div>
	
	<!-- chat dialog -->
	<div id="chat_dialog" class="hidden">
		<label>JID:</label><input type="text" id="chat-jid">
	</div>
	
	<!-- approval dialog -->
	<div id="approve_dialog" class="hidden">
		<p><span id="approve-jid"></span> has requested a subscription to your presence. Approve or deny?</p>
	</div>
</body>
</html>